#ifndef LIBTELNET_H
#define LIBTELNET_H

#include <stddef.h>
#include <stdint.h>
#include <string.h>


/* 平台兼容性定义 */
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
// 仅在MSVC编译器下使用#pragma comment
#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib")
#endif
#define TELNET_SOCKET SOCKET
#define TELNET_INVALID_SOCKET INVALID_SOCKET
#define TELNET_ERROR WSAGetLastError()
#else
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>

#define TELNET_SOCKET int
#define TELNET_INVALID_SOCKET -1
#define TELNET_ERROR errno
#endif

/* Telnet 命令码 */
#define TELNET_IAC 255 /*  Interpret As Command */
#define TELNET_DONT 254
#define TELNET_DO 253
#define TELNET_WONT 252
#define TELNET_WILL 251
#define TELNET_SB 250 /*  Subnegotiation Begin */
#define TELNET_SE 240 /*  Subnegotiation End */

/* Telnet 选项 */
#define TELNET_ECHO 1
#define TELNET_SUPPRESS_GO_AHEAD 3
# if 0 // todo: this never used, why
#define TELNET_STATUS 5
#define TELNET_TIMING_MARK 6
#define TELNET_TERMINAL_TYPE 24
#define TELNET_WINDOW_SIZE 31
#define TELNET_LINE_MODE 34
#define TELNET_ENVIRON 36
#endif 
/* 事件类型 */
typedef enum {
  TELNET_EVENT_DATA,        /* 接收到普通数据 */
  TELNET_EVENT_ERROR,       /* 错误发生 */
  TELNET_EVENT_CONNECTED,   /* 连接成功 */
  TELNET_EVENT_DISCONNECTED /* 连接断开 */
} telnet_event_type;

/* 错误类型 */
typedef enum {
  TELNET_ERROR_NONE,
  TELNET_ERROR_SOCKET,
  TELNET_ERROR_CONNECT,
  TELNET_ERROR_SEND,
  TELNET_ERROR_RECV,
  TELNET_ERROR_PROTOCOL
} telnet_error_type;

/* 事件结构 */
typedef struct {
  telnet_event_type type;
  union {
    struct {
      const char *data;
      size_t length;
    } data;
    struct {
      telnet_error_type code;
      const char *message;
    } error;
  } event;
} telnet_event;

/* 会话状态 */
typedef enum {
  TELNET_STATE_DISCONNECTED,
  TELNET_STATE_CONNECTING,
  TELNET_STATE_CONNECTED
} telnet_state;

/* 解析状态 */
typedef enum {
  TELNET_PARSE_NORMAL,
  TELNET_PARSE_IAC,
  TELNET_PARSE_COMMAND,
  TELNET_PARSE_SUBNEG
} telnet_parse_state;

/* Telnet 会话结构 */
typedef struct {
  TELNET_SOCKET sock;
  telnet_state state;
  telnet_parse_state parse_state;
  uint8_t current_option;
  char *recv_buffer;
  size_t recv_buffer_size;
  size_t recv_buffer_used;
  char *subneg_buffer;
  size_t subneg_buffer_size;
  size_t subneg_buffer_used;
} telnet_session;

/* 回调函数类型 */
typedef void (*telnet_event_handler)(telnet_session *session,
                                     const telnet_event *event);

/* 函数声明 */
telnet_session *telnet_create(size_t buffer_size);
void telnet_destroy(telnet_session *session);
int telnet_connect(telnet_session *session, const char *host, uint16_t port);
int telnet_disconnect(telnet_session *session);
int telnet_send(telnet_session *session, const char *data, size_t length);
int telnet_process(telnet_session *session, telnet_event_handler handler);
int telnet_send_command(telnet_session *session, uint8_t command,
                        uint8_t option);
int telnet_negotiate(telnet_session *session, uint8_t will, uint8_t option);

#endif /* LIBTELNET_H */

#ifdef LIBTELNET_IMPLEMENTATION

/* 平台初始化 */
static int telnet_platform_init(void) {
#ifdef _WIN32
  WSADATA wsaData;
  return WSAStartup(MAKEWORD(2, 2), &wsaData);
#else
  return 0;
#endif
}

/* 平台清理 */
static void telnet_platform_cleanup(void) {
#ifdef _WIN32
  WSACleanup();
#endif
}

/* 创建会话 */
telnet_session *telnet_create(size_t buffer_size) {
  static int platform_initialized = 0;
  if (!platform_initialized) {
    if (telnet_platform_init() != 0) {
      return NULL;
    }
    platform_initialized = 1;
  }

  telnet_session *session = (telnet_session *)malloc(sizeof(telnet_session));
  if (!session)
    return NULL;

  session->sock = TELNET_INVALID_SOCKET;
  session->state = TELNET_STATE_DISCONNECTED;
  session->parse_state = TELNET_PARSE_NORMAL;
  session->current_option = 0;

  session->recv_buffer_size = buffer_size;
  session->recv_buffer_used = 0;
  session->recv_buffer = (char *)malloc(buffer_size);
  if (!session->recv_buffer) {
    free(session);
    return NULL;
  }

  session->subneg_buffer_size = 1024;
  session->subneg_buffer_used = 0;
  session->subneg_buffer = (char *)malloc(session->subneg_buffer_size);
  if (!session->subneg_buffer) {
    free(session->recv_buffer);
    free(session);
    return NULL;
  }

  return session;
}

/* 销毁会话 - 调用平台清理函数 */
void telnet_destroy(telnet_session *session) {
  if (!session)
    return;

  telnet_disconnect(session);
  free(session->recv_buffer);
  free(session->subneg_buffer);
  free(session);

  // 清理平台资源（仅在最后一个会话销毁时）
  static int session_count = 0;
  if (--session_count <= 0) {
    telnet_platform_cleanup();
    session_count = 0;
  }
}

/* 连接到服务器 */
int telnet_connect(telnet_session *session, const char *host, uint16_t port) {
  if (!session || !host)
    return -1;

  if (session->state != TELNET_STATE_DISCONNECTED) {
    telnet_disconnect(session);
  }

  /* 创建socket */
  session->sock = socket(AF_INET, SOCK_STREAM, 0);
  if (session->sock == TELNET_INVALID_SOCKET) {
    return -1;
  }

  /* 设置服务器地址 */
  struct sockaddr_in server_addr;
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(port);

  /* 解析主机名 */
  if (inet_pton(AF_INET, host, &server_addr.sin_addr) <= 0) {
#ifdef _WIN32
    struct hostent *he = gethostbyname(host);
#else
    struct hostent *he = gethostbyname2(host, AF_INET);
#endif
    if (!he) {
      telnet_disconnect(session);
      return -1;
    }
    memcpy(&server_addr.sin_addr.s_addr, he->h_addr, he->h_length);
  }

  /* 连接服务器 */
  session->state = TELNET_STATE_CONNECTING;
  if (connect(session->sock, (struct sockaddr *)&server_addr,
              sizeof(server_addr)) == -1) {
    telnet_disconnect(session);
    return -1;
  }

  session->state = TELNET_STATE_CONNECTED;
  return 0;
}

/* 断开连接 */
int telnet_disconnect(telnet_session *session) {
  if (!session)
    return -1;

  if (session->sock != TELNET_INVALID_SOCKET) {
#ifdef _WIN32
    closesocket(session->sock);
#else
    close(session->sock);
#endif
    session->sock = TELNET_INVALID_SOCKET;
  }

  session->state = TELNET_STATE_DISCONNECTED;
  session->parse_state = TELNET_PARSE_NORMAL;
  session->recv_buffer_used = 0;
  session->subneg_buffer_used = 0;

  return 0;
}

/* 发送数据 */
int telnet_send(telnet_session *session, const char *data, size_t length) {
  if (!session || !data || length == 0 ||
      session->state != TELNET_STATE_CONNECTED ||
      session->sock == TELNET_INVALID_SOCKET) {
    return -1;
  }

  /* 需要转义IAC字符 */
  char *escaped = (char *)malloc(length * 2);
  if (!escaped)
    return -1;

  size_t escaped_len = 0;
  for (size_t i = 0; i < length; i++) {
    if (data[i] == TELNET_IAC) {
      escaped[escaped_len++] = TELNET_IAC;
      escaped[escaped_len++] = TELNET_IAC;
    } else {
      escaped[escaped_len++] = data[i];
    }
  }

  ssize_t sent = send(session->sock, escaped, escaped_len, 0);
  free(escaped);

  return (sent == (ssize_t)escaped_len) ? 0 : -1;
}

/* 发送命令 - 修复类型转换问题 */
int telnet_send_command(telnet_session *session, uint8_t command,
                        uint8_t option) {
  if (!session || session->state != TELNET_STATE_CONNECTED ||
      session->sock == TELNET_INVALID_SOCKET) {
    return -1;
  }

  char cmd[3] = {(char)TELNET_IAC, (char)command, (char)option};
  ssize_t sent = send(session->sock, cmd, 3, 0);
  return (sent == 3) ? 0 : -1;
}

/* 选项协商 */
int telnet_negotiate(telnet_session *session, uint8_t will, uint8_t option) {
  return telnet_send_command(session, will ? TELNET_WILL : TELNET_DO, option);
}

/* 处理接收到的数据 */
static void telnet_parse_data(telnet_session *session, const char *data,
                              size_t length, telnet_event_handler handler) {
  if (!session || !data || length == 0 || !handler)
    return;

  telnet_event event;

  for (size_t i = 0; i < length; i++) {
    uint8_t c = (uint8_t)data[i];

    switch (session->parse_state) {
    case TELNET_PARSE_NORMAL:
      if (c == TELNET_IAC) {
        session->parse_state = TELNET_PARSE_IAC;
      } else {
        /* 添加到缓冲区 */
        if (session->recv_buffer_used < session->recv_buffer_size) {
          session->recv_buffer[session->recv_buffer_used++] = c;
        }
      }
      break;

    case TELNET_PARSE_IAC:
      if (c == TELNET_IAC) {
        /* 转义的IAC，作为普通数据处理 */
        if (session->recv_buffer_used < session->recv_buffer_size) {
          session->recv_buffer[session->recv_buffer_used++] = c;
        }
        session->parse_state = TELNET_PARSE_NORMAL;
      } else if (c == TELNET_SB) {
        /* 子协商开始 */
        session->parse_state = TELNET_PARSE_SUBNEG;
        session->subneg_buffer_used = 0;
      } else if (c == TELNET_WILL || c == TELNET_WONT || c == TELNET_DO ||
                 c == TELNET_DONT) {
        /* 命令，等待选项 */
        session->parse_state = TELNET_PARSE_COMMAND;
        session->current_option = c;
      } else {
        /* 未知命令，忽略 */
        session->parse_state = TELNET_PARSE_NORMAL;
      }
      break;

    case TELNET_PARSE_COMMAND:
      /* 处理命令和选项 */
      if (session->current_option == TELNET_DO && c == TELNET_ECHO) {
        /* 服务器想要我们开启回声，我们拒绝 */
        telnet_send_command(session, TELNET_WONT, TELNET_ECHO);
      } else if (session->current_option == TELNET_DO &&
                 c == TELNET_SUPPRESS_GO_AHEAD) {
        /* 服务器想要我们关闭GO AHEAD，我们同意 */
        telnet_send_command(session, TELNET_WILL, TELNET_SUPPRESS_GO_AHEAD);
      }
      session->parse_state = TELNET_PARSE_NORMAL;
      break;

    case TELNET_PARSE_SUBNEG:
      if (c == TELNET_IAC) {
        /* 检查是否是子协商结束 */
        if (i + 1 < length && data[i + 1] == TELNET_SE) {
          i++; /* 跳过SE */
          session->parse_state = TELNET_PARSE_NORMAL;
        } else {
          /* 处理转义的IAC */
          if (session->subneg_buffer_used < session->subneg_buffer_size) {
            session->subneg_buffer[session->subneg_buffer_used++] = c;
          }
        }
      } else {
        /* 添加到子协商缓冲区 */
        if (session->subneg_buffer_used < session->subneg_buffer_size) {
          session->subneg_buffer[session->subneg_buffer_used++] = c;
        }
      }
      break;
    }
  }

  /* 如果有数据，发送数据事件 */
  if (session->recv_buffer_used > 0) {
    event.type = TELNET_EVENT_DATA;
    event.event.data.data = session->recv_buffer;
    event.event.data.length = session->recv_buffer_used;
    handler(session, &event);

    /* 清空缓冲区 */
    session->recv_buffer_used = 0;
  }
}

/* 处理会话 */
int telnet_process(telnet_session *session, telnet_event_handler handler) {
  if (!session || !handler)
    return -1;

  if (session->state == TELNET_STATE_CONNECTED &&
      session->sock != TELNET_INVALID_SOCKET) {
    /* 检查是否有数据可读 */
#ifdef _WIN32
    fd_set read_fds;
    FD_ZERO(&read_fds);
    FD_SET(session->sock, &read_fds);

    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 10000; /* 10ms超时 */

    int ret = select(0, &read_fds, NULL, NULL, &timeout);
#else
    fd_set read_fds;
    FD_ZERO(&read_fds);
    FD_SET(session->sock, &read_fds);

    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 10000; /* 10ms超时 */

    int ret = select(session->sock + 1, &read_fds, NULL, NULL, &timeout);
#endif

    if (ret > 0 && FD_ISSET(session->sock, &read_fds)) {
      /* 读取数据 */
      char buffer[4096];
      ssize_t bytes_read = recv(session->sock, buffer, sizeof(buffer), 0);

      if (bytes_read <= 0) {
        /* 连接关闭或出错 */
        telnet_event event;
        event.type = TELNET_EVENT_DISCONNECTED;
        handler(session, &event);
        telnet_disconnect(session);
        return -1;
      }

      /* 解析数据 */
      telnet_parse_data(session, buffer, (size_t)bytes_read, handler);
    } else if (ret < 0) {
      /* 错误发生 */
      telnet_event event;
      event.type = TELNET_EVENT_ERROR;
      event.event.error.code = TELNET_ERROR_RECV;
      event.event.error.message = "接收数据错误";
      handler(session, &event);
      return -1;
    }

    return 0;
  } else if (session->state == TELNET_STATE_CONNECTING) {
    /* 检查连接是否完成 */
#ifdef _WIN32
    fd_set write_fds;
    FD_ZERO(&write_fds);
    FD_SET(session->sock, &write_fds);

    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 0;

    int ret = select(0, NULL, &write_fds, NULL, &timeout);
#else
    fd_set write_fds;
    FD_ZERO(&write_fds);
    FD_SET(session->sock, &write_fds);

    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 0;

    int ret = select(session->sock + 1, NULL, &write_fds, NULL, &timeout);
#endif

    if (ret > 0 && FD_ISSET(session->sock, &write_fds)) {
      /* 连接成功 */
      session->state = TELNET_STATE_CONNECTED;

      telnet_event event;
      event.type = TELNET_EVENT_CONNECTED;
      handler(session, &event);

      /* 发送初始协商 */
      telnet_negotiate(session, 1, TELNET_SUPPRESS_GO_AHEAD);
      telnet_negotiate(session, 0, TELNET_ECHO);
    }

    return 0;
  }

  return -1;
}

#endif /* LIBTELNET_IMPLEMENTATION */
